﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.Game
{
    /// <summary>
    /// 类名 : 无规则布局的列表
    /// 作者 : Canyon / 龚阳辉
    /// 日期 : 2024-07-15 17:13
    /// 功能 : 元素固定，不能动态创建子元素
    /// </summary>
    /// <typeparam name="T">UIBaseNode</typeparam>
    public class IrregularListAdapter<T> : IUIList where T : UIBaseNode, new()
    {
        public int totalCount { get; private set; } = -1;
        // 必选项，刷新复用的item用
        private Action<T, int> callIUnitChanged;
        private UIBaseWindow belongWindow = null;
        private List<T> listActives = null;
        private Queue<T> pools = null;
        private GameObject gobjRoot = null;
        private int childCount = 0;
        private bool isRootActive = false;

        private ListUnitMappingData<T> dataMapping;
        private ListUnitSelect<T> unitSelect;
        private ListUnitUpdate<T> unitUpdate;
        public UnitSelectType selectedType { get => unitSelect.selectedType; set => unitSelect.selectedType = value; }
        public int selectedIndex => unitSelect.selectedIndex;

        public IrregularListAdapter(GameObject rootGo, UIBaseWindow baseWindow)
        {
            this.belongWindow = baseWindow;
            this.gobjRoot = rootGo;
            this.isRootActive = this.gobjRoot.activeSelf;

            int cnt = rootGo.transform.childCount;
            int halfCnt = Mathf.CeilToInt(cnt / 2f);
            this.childCount = cnt;
            this.listActives = new(halfCnt);
            this.pools = new(halfCnt);
            this.dataMapping = new ListUnitMappingData<T>(halfCnt);

            this.InitFixedNode();
        }

        public IrregularListAdapter<T> BindUnitChangedCall(Action<T, int> funcChanged)
        {
            this.callIUnitChanged = funcChanged;
            return this;
        }

        public IrregularListAdapter<T> InitUnitSelected(UnitSelectType selectedType, Action<int, T> funcSelected, Action<int, T> funcUnSelected = null)
        {
            return InitUnitSelected(new ListUnitSelect<T>.UnitSelectData()
            {
                selectedType = selectedType,
                callSelected = funcSelected,
                callUnSelected = funcUnSelected,
            });
        }

        public IrregularListAdapter<T> InitUnitSelected(ListUnitSelect<T>.UnitSelectData data)
        {
            if (this.unitSelect == null)
            {
                this.unitSelect = new ListUnitSelect<T>(this.dataMapping);
                this.unitSelect.Initialize(data);
            }
            return this;
        }

        public IrregularListAdapter<T> SetUnitMitiSelect(int maxSelected, Action funcFullWhenSelectOther = null)
        {
            if (this.unitSelect != null)
            {
                this.unitSelect.SetMitiSelect(maxSelected, funcFullWhenSelectOther);
            }
            return this;
        }

        public IrregularListAdapter<T> InitUnitUpdate()
        {
            if (this.unitUpdate == null)
            {
                this.unitUpdate = new ListUnitUpdate<T>(this.dataMapping);
                this.unitUpdate.AddUpdate();
            }
            return this;
        }

        private void InitFixedNode()
        {
            foreach (Transform child in this.gobjRoot.transform)
            {
                T newitem = new T();
                newitem.Init(child.gameObject, this.belongWindow);
                this.pools.Enqueue(newitem);
            }
        }

        private void HideAfter(int indexBegHide)
        {
            if (indexBegHide < 0 || indexBegHide > this.listActives.Count)
                return;
            for (int i = this.listActives.Count - 1; i >= indexBegHide; i--)
            {
                T node = this.listActives[i];

                this.listActives.Remove(node);
                node.Hide();
                this.pools.Enqueue(node);
            }
        }

        private T GetActiveOne(int index)
        {
            if (index < 0)
                return null;
            var cnt = this.listActives.Count;
            if (cnt <= index)
                return null;
            return this.listActives[index];
        }

        public void RefillCells(int totalCount, int selectIndex = -1)
        {
            this.SetActive(true);
            this.totalCount = totalCount;
            this.dataMapping.EmptyMapping();
            this.unitSelect?.ReIniteListUnits();
            this.HideAfter(totalCount);

            T node = null;
            for (int i = 0; i < totalCount; i++)
            {
                node = this.GetActiveOne(i);
                if (node == null)
                {
                    this.pools.TryDequeue(out node);
                    if (node == null)
                    {
                        throw new IndexOutOfRangeException($"Fixed List,index = {i} , Child Count ={this.childCount}");
                    }
                    this.listActives.Add(node);
                }

                this.OnCreateItem(node, i);
                this.OnItemDataChange(node, i);
                this.OnInitSelected(node, i);
            }

            this.unitSelect?.ComplateIniteListUnits();
            this.ResetSelected(selectIndex);
        }

        private void OnCreateItem(T node, int index)
        {
            this.dataMapping.InitTUnitMapping(node);
            this.dataMapping.InitIndexMapping(node, index);
        }

        private void OnItemDataChange(T node, int index)
        {
            callIUnitChanged?.Invoke(node, index);
        }

        private void OnInitSelected(T node, int index)
        {
            this.unitSelect?.Refresh(node, index);
        }

        public void ResetSelected(int selectIndex)
        {
            this.unitSelect?.SetSelected(selectIndex, true);
        }

        public T GetTEntity(int index)
        {
            return this.dataMapping.GetTEntity(index);
        }

        public void SetActive(bool isActive)
        {
            if (this.isRootActive != isActive)
            {
                this.isRootActive = isActive;
                this.gobjRoot?.SetActive(isActive);
            }
        }

        public void RefreshCells()
        {
            var activeUnits = this.dataMapping.GetActiveUnits();
            foreach (var unit in activeUnits)
            {
                if (this.dataMapping.TryGetIndex(unit.gameObject, out var index))
                {
                    this.OnItemDataChange(unit, index);
                }
            }
        }

        public void Clear()
        {
            this.totalCount = -1;
            this.callIUnitChanged = null;
            this.belongWindow = null;
            this.gobjRoot = null;
            this.isRootActive = false;

            this.unitSelect?.Clear();
            this.unitSelect = null;
            this.dataMapping?.ClearExcludeUnits();
            this.dataMapping = null;
            this.unitUpdate?.Clear();
            this.unitUpdate = null;
            this.ClearNodes();
        }

        private void ClearNodes()
        {
            if (this.pools != null)
            {
                while (this.pools.Count > 0)
                {
                    var item = this.pools.Dequeue();
                    item.Dispose();
                }
            }
            this.pools = null;
            if (this.listActives != null)
            {
                foreach (var item in this.listActives)
                {
                    item.Dispose();
                }
                this.listActives.Clear();
            }
            this.listActives = null;
        }
    }
}
